package mop.domain.resource;

import java.sql.Timestamp;
import java.util.LinkedList;
import java.util.List;

import mop.domain.task.Task;
import mop.exception.IllegalDescriptionException;
import mop.exception.IllegalReservationException;
import mop.exception.UnavailableResourceException;

/**
 * Abstracte klasse Resource.
 * 
 * @invar 	description is valid
 *  		|hasValidDescription()
 * 
 * @author	MOP Team 7
 */
public abstract class Resource 
{
	/**
	 * Creates a Resource with a description.
	 * 
	 * @param 	description
	 *  		The description of the resource.
	 *  
	 * @effect 	Sets the description.
	 *       
	 * @throws 	IllegalDescriptionException
	 * 			if the description isn't a non-empty string
	 * 			|!isValidDescription(description) 
	 */
	public Resource(String description) 
		throws IllegalDescriptionException
	{
		this.setDescription(description);
		this.reservations = new LinkedList<Reservation>();
		this.tasksRequiring = new LinkedList<Task>();
	}
	
	
	/***************************************************************************
	 * 							resource description
	 ***************************************************************************/
	
	/**
	 * Returns the description for this resource.
	 * 
	 * @return 	description;
	 */
	public String getDescription()
	{
		return this.description;
	}
	
	 /**
	  * Checks if the given description is ok.
	  * 
	  * @param 	description
	  *  		The description to check.
	  * 
	  * @return true if the given description is not empty and not null.
	  */
	 public static boolean isValidDescription(String description)
	 {
		 return ((!(description.trim().equals("")) && description != null));
	 }
	
	 /**
	  * Sets the description.
	  * 
	  * @param 	description
	  *  		The description of the resource.
	  *  
	  * @post 	The description is set.
	  *  
	  * @throws IllegalDescriptionException 
	  *       	if the description isn't ok
	  *       	|!isValidDescription(description)
	  *    
	  */
	 private void setDescription(String description) 
	 	throws IllegalDescriptionException
	 {
		 if(!isValidDescription(description))
		 {
			 throw new IllegalDescriptionException(description);
		 }
		 
		 this.description = description;
	 }
	
	 /**
	  * variable for the description of the resource
	  */
	private String description;
	
	
	/***************************************************************************
	 * 					  Tasks requiring this resource
	 ***************************************************************************/
	
	/**
	 * Returns a list of tasks requiring this resource.
	 * 
	 * @return A list of tasks requiring this resource.
	 */
	public List<Task> getTasksRequiring()
	{
		return this.tasksRequiring;
	}
	
	/** A list of tasks requiring this resource. */
	private List<Task> tasksRequiring;
	
	
	/***************************************************************************
	 * 						     Reservation
	 ***************************************************************************/
	
	/**
	 * Adds a reservation for this resource.
	 * 
	 * @param 	start
	 * 			The start time as a Timestamp.
	 * @param	end
	 * 			The end time as a Timestamp.
	 * 
	 * @post	A reservation for the resource is made (added to reservations list).
	 * 			| reservations.contains( new Reservation(start, end) )
	 * 
	 * @throws	IllegalReservationException
	 * 			If the start time is greater than the end time.
	 * @throws	UnavailableResourceException 
	 * 			If the resource is unavailable at that time.
	 */
	public void addReservation(Timestamp start, Timestamp end) 
		throws IllegalReservationException, UnavailableResourceException
	{
		Reservation r = new Reservation(start, end);
		
		if(this.isAvailable(start, end))
			this.reservations.add(r);
		else
			throw new UnavailableResourceException(this.getDescription());
	}
	
	/**
	 * Returns a list of reservations for this Resource.
	 * 
	 * @return	A list of Reservation objects.
	 */
	public List<Reservation> getReservations()
	{
		return this.reservations;
	}
	
	/**
	 * Checks whether this Resource is available or not.
	 * A Resource is available if the current time isn't between 
	 * the start and end of a reservation for that Resource.
	 * 
	 * @return	True if the Resource is available, otherwise false.
	 */
	public boolean isAvailable()
	{
		return this.isAvailable( new Timestamp(System.currentTimeMillis()) );
	}
	
	/**
	 * Checks whether this Resource is available at the given timePeriod or not.
	 * A Resource is available if the give timePeriod isn't between 
	 * the start and end of a reservation for that Resource.
	 * 
	 * @param	timePeriod
	 * 			A time stamp.
	 * 
	 * @pre		timePeriod must be initialized.
	 * 
	 * @return	True if the Resource is available, otherwise false.
	 */
	public boolean isAvailable(Timestamp timePeriod)
	{
		for(Reservation r : this.getReservations())
			if(r.isDuring(timePeriod))
				return false;
		
		return true;
	}
	
	/**
	 * Checks whether this Resource can be reserved between a given time period or not.
	 * 
	 * @param	start
	 * 			A time stamp.
	 * @param	end
	 * 			A time stamp.
	 * 
	 * @pre		start must be initialized.
	 * @pre		end must be initialized.
	 * @pre		end must be AFTER start!
	 * 
	 * @return	True if the Resource is available, otherwise false.
	 */
	public boolean isAvailable(Timestamp start, Timestamp end)
	{
		for(Reservation r : this.getReservations())
			if( (r.getStart().before(start) && r.getEnd().after(start)) ||
				(r.getStart().before(end) && r.getEnd().after(end)) )
					return false;
		
		return true;
	}
	
	/**
	 * List of reservations of this resource.
	 */
	private LinkedList<Reservation> reservations;
	
	
	/***************************************************************************
	 * 						Java Object interface
	 ***************************************************************************/
	
	/**
	 * Returns a string representing this Resource.
	 * 
	 * @return	A string with on the first line this.getDescription.
	 */
	public String toString()
	{
		return this.getDescription();
	}
	
}
